package com.yuandianrrp.log.jdalog;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.yuandianrrp.log.jdalog.job.JobFileAppender;
import com.yuandianrrp.log.jdalog.job.JobLogger;
import com.yuandianrrp.log.jdalog.utils.SystemUtils;
import com.yuandianrrp.log.jdalog.utils.WeightLoginUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Administrator
 */
public class JpaLogUtils {
    /**
     * 线程间隔
     */
    public static final Integer SLEEP = 300;
    private static final String BUSINESS_NAME = "Weight";
    private static final Logger logger = LoggerFactory.getLogger(BUSINESS_NAME);
    private static final Integer dbCacheSize = 1024 * 10;
    private static LinkedBlockingQueue<Runnable> QUEUE = new LinkedBlockingQueue<>(2048);
    private static ExecutorService threadPoolExecutor;

    static {
        AtomicInteger integer = new AtomicInteger(0);
        threadPoolExecutor = new ThreadPoolExecutor(8, 16, 1000,
                TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(16),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                        //线程命名
                        return new Thread(r, "log-append-" + integer.incrementAndGet());
                    }
                }, new ThreadPoolExecutor.CallerRunsPolicy());
        JobFileAppender.makeLogFileName(BUSINESS_NAME);
        new Thread(new appendLogFileTask(), "LogRecordAppendService").start();
    }


    /**
     * 初始化
     *
     * @param record
     */
    public static void put(Runnable record) {
        try {
            QUEUE.put(record);
        } catch (InterruptedException e) {
            logger.error(e.getMessage(), e);
        }
    }

    static class appendLogFileTask implements Runnable {
        @Override
        public void run() {
            while (true) {
                if (!SystemUtils.getSystemStatus()) {
                    List<Runnable> list = new ArrayList<Runnable>();
                    QUEUE.drainTo(list, dbCacheSize);
                    if (!CollectionUtil.isEmpty(list)) {
                        for (Runnable runnable : list) {
                            threadPoolExecutor.submit(runnable);
                        }
                    }
                }
                ThreadUtil.safeSleep(SLEEP);
            }
        }
    }

    /**
     * info
     *
     * @param info
     */
    public static void info(String info) {
        String name = Thread.currentThread().getName();
        StackTraceElement callInfo = new Throwable().getStackTrace()[2];
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                JobLogger.log(callInfo, BUSINESS_NAME, name, info);
            }
        };
        put(runnable);
    }

    /**
     * 日志记录
     *
     * @param format
     * @param argArray
     */
    public static void info(String format, Object... argArray) {
        StackTraceElement callInfo = new Throwable().getStackTrace()[3];
        String name = Thread.currentThread().getName();
        put(new Runnable() {
            @Override
            public void run() {
                FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
                String appendLog = ft.getMessage();
                JobLogger.log(callInfo, BUSINESS_NAME, name, appendLog);
            }
        });
    }

    /**
     * warning
     *
     * @param warning
     */
    public static void warning(String warning) {
        put(new Runnable() {
            @Override
            public void run() {
                logger.warn(WeightLoginUtils.formatDateTime(new Date()) + "_" + warning);
            }
        });
    }


    public static void error(String info) {
        StackTraceElement callInfo = new Throwable().getStackTrace()[3];
        String name = Thread.currentThread().getName();
        put(new Runnable() {
            @Override
            public void run() {
                JobLogger.log(callInfo, BUSINESS_NAME, name, info);
            }
        });
    }

    /**
     * 发生错误
     *
     * @param warning   错误消息
     * @param throwable 异常的栈
     */
    public static void error(String warning, Throwable throwable) {
        StackTraceElement callInfo = new Throwable().getStackTrace()[3];
        String name = Thread.currentThread().getName();
        put(new Runnable() {
            @Override
            public void run() {
                logger.error(WeightLoginUtils.formatDateTime(new Date()) + "_" + warning, throwable);
                JobLogger.log(callInfo, BUSINESS_NAME, throwable, name);
            }
        });
    }
}
